package com.fneuch.mwg.w40k.rule;

import org.springframework.stereotype.Component;

import com.fneuch.mwg.army.Unit;
import com.fneuch.mwg.profiles.CloseCombatProfile;
import com.fneuch.mwg.profiles.DefenseProfile;
import com.fneuch.mwg.profiles.ModelProfile;
import com.fneuch.mwg.rules.AttackResult;
import com.fneuch.mwg.rules.CloseCombatRuleEngine;
import com.fneuch.mwg.rules.shooting.ShootingResult;

@Component
public class CloseCombatEngine extends AbstractRuleEngine implements CloseCombatRuleEngine {
	private static int[][] toHitChart = {
		{4, 4, 5, 5, 5, 5, 5, 5, 5, 5}, // WS 1
		{3, 4, 4, 5, 5, 5, 5, 5, 5, 5}, // WS 2
		{3, 3, 4, 4, 5, 5, 5, 5, 5, 5}, // WS 3
		{3, 3, 3, 4, 4, 5, 5, 5, 5, 5}, // WS 4
		{3, 3, 3, 3, 4, 4, 5, 5, 5, 5}, // WS 5
		{3, 3, 3, 3, 3, 4, 4, 5, 5, 5}, // WS 6
		{3, 3, 3, 3, 3, 3, 4, 4, 5, 5}, // WS 7
		{3, 3, 3, 3, 3, 3, 3, 4, 4, 5}, // WS 8
		{3, 3, 3, 3, 3, 3, 3, 3, 4, 4}, // WS 9
		{3, 3, 3, 3, 3, 3, 3, 3, 3, 4}, // WS 10
	};

	public int toWound(int strengthValue, int toughnessValue) {
		int retour = 0;
		int strengthNeeded = strengthValue-1 < 0 ? 0 : strengthValue-1;
		int toughnessNeeded = toughnessValue-1 < 0 ? 0 : toughnessValue-1;
		int statsNeeded = woundChart[strengthNeeded][toughnessNeeded];
		if(statsNeeded > 0) {
			retour = probability.over(statsNeeded); 
		}
		
		return retour;
	}

	@Override
	public AttackResult execute(Unit attacker, Unit defender) {
		ShootingResult result = attacker.getModels().isEmpty() ? null:new ShootingResult();
		int nbTotalDefenders = defender.getNbModels();
		int nbTotalAttacker = attacker.getNbModels();
		
		DefenseProfile averageDefenseProfile = (DefenseProfile) defender.getLargestNumberModel(defender);
		
		// The attacking side action 
		for(ModelProfile model:attacker.getModels().keySet()) {
			CloseCombatProfile fighter = (CloseCombatProfile)model;
			// Counting nb Shoot
			double nbShooter = attacker.getModels().get(model).intValue();
			result.setNbAttacks(result.getNbAttacks() + (int)nbShooter);
			// Counting hit hit
			double toHitPercent = toHit(fighter.getWeaponSkill(), averageDefenseProfile.getWeaponSkill()) ;
			result.setToHit(result.getToHit() + (int)(toHitPercent * (nbShooter / nbTotalAttacker)));
			result.setNbHits(result.getNbHits() + (int)Math.round(nbShooter * toHitPercent/100));
			// Counting total wound
			double toWoundPercent = toWound(fighter.getStrength(), averageDefenseProfile.getToughness()); 
			result.setToWound(result.getToWound() +  (int)(toWoundPercent * (nbShooter / nbTotalAttacker)));
			result.setNbWounded(result.getNbWounded() + (int)Math.round(result.getNbHits() * toWoundPercent/100));
		}
		
		// we must find an average save percentage
		for(ModelProfile model:defender.getModels().keySet()) {
			DefenseProfile defenderModel = (DefenseProfile)model;
			double nbDefender = defender.getModels().get(model).intValue();
			double toSavePercent = toSave(defenderModel.getSave()); 
			result.setToSave(result.getToSave() + (int)(toSavePercent   * (nbDefender / nbTotalDefenders)));
		}
		// Calculating defense result
		result.setNbSaved((int)Math.round(result.getNbWounded() * result.getToSave()/100));
		int damaged = result.getNbWounded()- result.getNbSaved();
		result.setNbDefenderLeft(nbTotalDefenders - damaged);

		return result;	
		}

	private double toHit(int weaponSkillAttacker, int weaponSkillDefender) {
		int result = 0;
		
		int statsNeeded = toHitChart[weaponSkillAttacker][weaponSkillDefender];
		if(statsNeeded > 0) {
			result = probability.over(statsNeeded); 
		}
		
		
		return result;

	}

}
